home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / plotting / pcgplots / cgmdispl.cpp < prev    next >
C/C++ Source or Header  |  1992-04-24  |  31KB  |  1,043 lines

  1. // C++ file for base display classes 
  2. // copyright 1992 Pittsburgh Supercomputing Center
  3. // these will only be called if the actual display used doesn't have its own
  4. #include <math.h>
  5. #include "cgm.h"
  6. #ifdef __MSDOS__
  7. #include "cgmdisp.h"
  8. #else
  9. #include "cgmdisplay.h"
  10. #endif
  11. #include "hload1.h"
  12. // error call
  13. extern void myError(const char *inMsg, const char *inMsg2=NULL,
  14.             int severity=1);
  15. ////
  16. // angle
  17. ////
  18. const double angle::tanMax = 1e10; // maximum tangent value
  19. #ifdef macintosh
  20.  #pragma segment DIS1
  21. #endif
  22. ////
  23. // hershey font stuff
  24. ////
  25. // hershey character
  26. ////
  27. const int hersheyChar::maxOffset = sizeof(hf_array);
  28. hersheyChar::hersheyChar(const genText *inText, int charNo, int fontNo)
  29. {
  30.   static const vdcPts *usePos = NULL;
  31.   int offset, i;
  32.   next = NULL;
  33.   contents = NULL;
  34.   if (!inText || (charNo > inText->size())) return; // safety check
  35.   ////
  36.   if (fontNo >= NO_HF) fontNo = 0; // existing font
  37.   int wantChar = inText->contents()[charNo]; // character we want
  38.   if ((wantChar < 0) || (wantChar >= MAX_HCHARS) ||
  39.       ((offset = h_array[fontNo][wantChar]) < 0) ||
  40.       (offset > maxOffset)) return; // no legal character
  41. //  if (hf_array[offset] < 0) return; // no such character in this font
  42.   float charSize = inText->info()->height() / 24; // 24 pixel square
  43.   // do we have any rotation ?
  44.   angle upVec(1, 0), baseVec(0, 1);
  45.   if (inText->info()->orientation()) {
  46.     upVec = angle(inText->info()->orientation()->y(0),
  47.           inText->info()->orientation()->x(0));
  48.     baseVec = angle(inText->info()->orientation()->y(1),
  49.             inText->info()->orientation()->x(1));
  50.   }
  51.   ////
  52.   // now we know we have some points
  53.   if (inText->pos()) usePos = inText->pos(); // may be appended
  54.   if (!usePos) return; // no where to put it
  55.   // figure out the shifts
  56.   unsigned char *hPtr = hf_array + offset;
  57.   float temp1 = charSize * (128 - (int) hPtr[0]);
  58.   float temp2 = charSize * ((int) hPtr[1] - 128);
  59.   myShift1 =  temp1 * baseVec.cos();
  60.   myShift2 =  temp2 * baseVec.cos();
  61.   myShiftY1 = temp1 * baseVec.sin();
  62.   myShiftY2 = temp2 * baseVec.sin();
  63.   myHeight = myDepth = 0;
  64.   // step over widths
  65.   hPtr +=2;
  66.   // prepare for loop
  67.   int noPts = 0;
  68.   float fx, fy;
  69.   do {
  70.     if (!hPtr[2*noPts] && (!hPtr[2*noPts+1] || (hPtr[2*noPts+1] == 128))) {
  71.       // pen coming up or end of character description
  72.       if (noPts) { // some to do
  73.     if (usePos->type()) { // real vdc's
  74.       float *newFloat = new float[noPts * 2];
  75.       for (i=0; i<noPts; ++i) {
  76.         fx = hPtr[2*i];
  77.         fx -= 128;
  78.         fx *= charSize;
  79.         fy = - (int) hPtr[2*i+1];
  80.         fy += 140; // + 12 for bottom of box
  81.         fy *= charSize;
  82.         if (fy > myHeight) myHeight = fy;
  83.         if (-fy > myDepth) myDepth = -fy;
  84.         newFloat[2*i] = fx * baseVec.cos() + fy * upVec.cos();
  85.         newFloat[2*i+1] = fy * upVec.sin() + fx * baseVec.sin();
  86.       }
  87.       addPts(new vdcPts(newFloat, noPts));
  88.     } else { // integer vdc's
  89.       int *newInt = new int[noPts * 2];
  90.       for (i=0; i<noPts; ++i) {
  91.         fx = hPtr[2*i];
  92.         fx -= 128;
  93.         fx *= charSize;
  94.         fy = - (int) hPtr[2*i+1];
  95.         fy += 140; // + 12 for bottom of box
  96.         fy *= charSize;
  97.         if (fy > myHeight) myHeight = fy;
  98.         if (-fy > myDepth) myDepth = -fy;
  99.         newInt[2*i] = (int) (fx * baseVec.cos() + fy * upVec.cos());
  100.         newInt[2*i+1] = (int) (fy * upVec.sin() + fx * baseVec.sin());
  101.       }
  102.       addPts(new vdcPts(newInt, noPts));
  103.     }
  104.       }
  105.       if (hPtr[2*noPts+1]) { // more to come
  106.     hPtr += noPts * 2 + 2;  // step over description
  107.     noPts = 0; // start fresh
  108.       } else break; // last polyline
  109.     } else ++noPts; // normal point
  110.   } while ((hPtr + noPts * 2) <= (hf_array + maxOffset)); // in legal position
  111. }
  112. ////
  113. // destructor
  114. ////
  115. hersheyChar::~hersheyChar()
  116. {
  117.   vdcPts *myPtr, *nextPtr;
  118.   for (myPtr = contents; myPtr; myPtr = nextPtr) {
  119.     nextPtr = myPtr->next;
  120.     delete myPtr;
  121.   }
  122. }
  123. ////
  124. // scale the character
  125. ////
  126. void hersheyChar::scale(float factor) 
  127. {
  128.   myShift1 *= factor;
  129.   myShift2 *= factor;
  130.   myShiftY1 *= factor;
  131.   myShiftY2 *= factor;
  132.   myHeight *= factor;
  133.   myDepth *= factor;
  134.   for (vdcPts *myPtr = contents; myPtr; myPtr = myPtr->next)
  135.     myPtr->scale(factor);
  136. }
  137. ////
  138. // add some pts to a single character
  139. ////
  140. void hersheyChar::addPts(vdcPts *inPts)
  141. {
  142.   if (!contents) contents = inPts;
  143.   else {
  144.     for (vdcPts *myPtr=contents; myPtr->next; myPtr = myPtr->next);
  145.     myPtr->next = inPts;
  146.   }
  147. }
  148. ////
  149. // display the character
  150. ////
  151. int hersheyChar::display(baseDisplay *inDisplay)
  152. {
  153.   int ret = 1;
  154.   for (vdcPts *myPtr=contents; myPtr; myPtr=myPtr->next) {
  155.     ret = ret && inDisplay->polyline(myPtr);
  156.   }
  157.   return ret;
  158. }
  159. ////
  160. // shift the character
  161. ////
  162. void hersheyChar::shift(float &xShift, float &yShift)
  163. {
  164.   for (vdcPts *myPtr=contents; myPtr; myPtr=myPtr->next) {
  165.     myPtr->shift(xShift, yShift);
  166.   }
  167. }
  168. ////
  169. // hershey string
  170. ////
  171. hersheyString::hersheyString(const genText *inText) // constructor
  172. {
  173.   static float xStart, yStart;
  174.   contents = NULL;
  175.   myHeight = myDepth = 0;
  176.   ////
  177.   // create all of the characters
  178.   for (int i=0; i<inText->size(); ++i)
  179.     addChar(new hersheyChar(inText, i));
  180.   ////
  181.   if (inText->pos()) { // may be appended text
  182.     xStart = inText->pos()->x(0);
  183.     yStart = inText->pos()->y(0);
  184.   }
  185.   // is this restricted text ?
  186.   const vdc *inW, *inH;
  187.   if ((inW = inText->width()) && (inH = inText->height())) {
  188.     float inWidth = inW->f();
  189.     float inHeight = inH->f();
  190.     float h = height();
  191.     float d = depth();
  192.     float w = width();
  193.     if (inText->info()) w *= inText->info()->expan();
  194.     if (d > 0) h += d;
  195.     if (h && w) {
  196.       float xHScale = inWidth / w;
  197.       float yHScale = inHeight / h;
  198.       float useHScale = (xHScale < yHScale) ? xHScale : yHScale;
  199.       scale(useHScale); // scale the string
  200.       if (d > 0) yStart += d * useHScale;
  201.     }
  202.   }
  203. //  float yStart1 = yStart;
  204.   // now take care of positioning
  205.   float trueWidth = width(); // figure out true width of string
  206.   if (inText->info()) trueWidth *= inText->info()->expan();
  207.   ////
  208.   if (inText->info()->align()) {
  209.     switch(inText->info()->align()->h()) {
  210.     case 0:
  211.     case 1: break; // ok
  212.     case 2: xStart -= 0.5 * trueWidth; break;
  213.     case 3: xStart -= trueWidth; break;
  214.     case 4: break; // fix later
  215.     }
  216.     switch(inText->info()->align()->v()) {
  217.     case 0: break; // ok
  218.     case 1: yStart -= height(); break;
  219.     case 2: yStart -= 0.9 * height(); break;
  220.     case 3: yStart -= 0.5 * height(); break;
  221.     case 4: yStart -= 0.1 * height(); break;
  222.     case 5:  break;
  223.     case 6 : break; // fix later
  224.     }
  225.   }
  226.   switch(inText->info()->path()) {
  227.   case 0:
  228.     right(inText, xStart, yStart); break;
  229.   case 1:
  230.     left(inText, xStart, yStart); break;
  231.   case 2:
  232.     up(inText, xStart, yStart); break;
  233.   case 3:
  234.     down(inText, xStart, yStart); break;
  235.   }
  236. }
  237. ////
  238. // string width
  239. ////
  240. float hersheyString::width() 
  241. {
  242.   float w=0;
  243.   for (hersheyChar *p=contents; p; p=p->next) w += p->width();
  244.   return w;
  245. }
  246. ////
  247. // scale the string
  248. ////
  249. void hersheyString::scale(float factor) 
  250. {
  251.   myHeight *= factor;
  252.   myDepth *= factor;
  253.   for (hersheyChar *p=contents; p; p=p->next) p->scale(factor);
  254. }
  255. ////
  256. // destructor
  257. ////
  258. hersheyString::~hersheyString() 
  259. {
  260.   hersheyChar *myPtr, *nextPtr;
  261.   for (myPtr = contents; myPtr; myPtr = nextPtr) {
  262.     nextPtr = myPtr->next;
  263.     delete myPtr;
  264.   }
  265. }
  266. ////
  267. // write out to the right
  268. ////
  269. void hersheyString::right(const genText *inText, float &xStart, float &yStart)
  270. {
  271.   angle upVec(1, 0), baseVec(0, 1);
  272.   float expand = 1;
  273.   if (inText->info()->orientation()) {
  274.     upVec = angle(inText->info()->orientation()->y(0),
  275.           inText->info()->orientation()->x(0));
  276.     baseVec = angle(inText->info()->orientation()->y(1),
  277.             inText->info()->orientation()->x(1));
  278.     if (upVec.size()) expand = baseVec.size() / upVec.size();
  279.   }
  280.   expand *= inText->info()->expan();
  281.   for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
  282.     xStart += myPtr->shift1() * expand;
  283.     yStart += myPtr->shiftY1();
  284.     myPtr->shift(xStart, yStart);
  285.     xStart += myPtr->shift2() * expand;
  286.     yStart += myPtr->shiftY2();
  287.   }
  288. }
  289. ////
  290. // write out to the left
  291. ////
  292. void hersheyString::left(const genText *inText, float &xStart, float &yStart)
  293. {
  294.   angle upVec(1, 0), baseVec(0, 1);
  295.   float expand = 1;
  296.   if (inText->info()->orientation()) {
  297.     upVec = angle(inText->info()->orientation()->y(0),
  298.           inText->info()->orientation()->x(0));
  299.     baseVec = angle(inText->info()->orientation()->y(1),
  300.             inText->info()->orientation()->x(1));
  301.     if (upVec.size()) expand = baseVec.size() / upVec.size();
  302.   }
  303.   expand *= inText->info()->expan();
  304.   for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
  305.     xStart -= myPtr->shift2() * expand;
  306.     yStart -= myPtr->shiftY2();
  307.     myPtr->shift(xStart, yStart);
  308.     xStart -= myPtr->shift1() * expand;
  309.     yStart -= myPtr->shiftY1();
  310.   }
  311. }
  312. ////
  313. // write up
  314. ////
  315. void hersheyString::up(const genText *inText, float &xStart, float &yStart)
  316. {
  317.   float x, expand = 1;
  318.   angle upVec(1, 0), baseVec(0, 1);
  319.   if (inText->info()->orientation()) {
  320.     upVec = angle(inText->info()->orientation()->y(0),
  321.           inText->info()->orientation()->x(0));
  322.     baseVec = angle(inText->info()->orientation()->y(1),
  323.             inText->info()->orientation()->x(1));
  324.     if (upVec.size()) expand = baseVec.size() / upVec.size();
  325.   }
  326.   expand *= inText->info()->expan();
  327.   for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
  328.     x = xStart + myPtr->shift1() * expand;
  329.     myPtr->shift(x, yStart);
  330.     yStart += myPtr->height() * upVec.sin();
  331.     xStart += myPtr->height() * upVec.cos();
  332.   }
  333. }
  334. ////
  335. // write down
  336. ////
  337. void hersheyString::down(const genText *inText, float &xStart, float &yStart)
  338. {
  339.   float x, expand = 1;
  340.   angle upVec(1, 0), baseVec(0, 1);
  341.   if (inText->info()->orientation()) {
  342.     upVec = angle(inText->info()->orientation()->y(0),
  343.           inText->info()->orientation()->x(0));
  344.     baseVec = angle(inText->info()->orientation()->y(1),
  345.             inText->info()->orientation()->x(1));
  346.     if (upVec.size()) expand = baseVec.size() / upVec.size();
  347.   }
  348.   expand *= inText->info()->expan();
  349.   for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next) {
  350.     x = xStart + myPtr->shift1() * expand;
  351.     myPtr->shift(x, yStart);
  352.     yStart -= myPtr->height() * upVec.sin();
  353.     xStart -= myPtr->height() * upVec.cos();
  354.   }
  355. }
  356. void hersheyString::addChar(hersheyChar *inChar)
  357. {
  358.   if (!contents) contents = inChar;
  359.   else {
  360.     for (hersheyChar *myPtr = contents; myPtr->next; myPtr = myPtr->next);
  361.     myPtr->next = inChar;
  362.     if (inChar->height() > myHeight) myHeight = inChar->height();
  363.     if (inChar->depth() > myDepth) myDepth = inChar->depth();
  364.   }
  365. }
  366. int hersheyString::display(baseDisplay *inDisplay)
  367. {
  368.   int ret = 1;
  369.   for (hersheyChar *myPtr=contents; myPtr; myPtr=myPtr->next)
  370.     ret = ret && myPtr->display(inDisplay);
  371.   return ret;
  372. }
  373. #ifdef macintosh
  374.  #pragma segment DIS2
  375. #endif
  376. ////
  377. // base display
  378. // constructor
  379. ////
  380. baseDisplay::baseDisplay()
  381. {
  382.   myPxlExtent = NULL;
  383. }  
  384. ////
  385. // graphical primitives
  386. ////
  387. // disjoint polyline
  388. ////
  389. int baseDisplay::disPolyline(const vdcPts *inPts) // emulate with a polyline
  390.      // we do the disjoint polyline 2 pairs of points at a time
  391. {
  392.   int i, j, ret = 1;
  393.   vdcPts *myPts = NULL;
  394.  
  395.   if (inPts->type()) { // real vdc's
  396.     float *newFloat = new float[4];
  397.     myPts = new vdcPts(newFloat, 2);
  398.  
  399.     for (i=0; (i<inPts->no()) && ret; i +=2) {
  400.       for (j=0; j<4; ++j) newFloat[j] = inPts->f(2*i+j);
  401.       ret = ret && polyline(myPts);
  402.     }
  403.   } else { // integer VDC's
  404.     int *newInt = new int[4];
  405.     myPts = new vdcPts(newInt, 2);
  406.  
  407.     for (i=0; (i<inPts->no()) && ret; i +=2) {
  408.       for (j=0; j<4; ++j) newInt[j] = inPts->i(2*i+j);
  409.       ret = ret && polyline(myPts);
  410.     }
  411.   }
  412.   delete myPts; // clean up
  413.   return ret;
  414. }
  415. ////
  416. // polymarker
  417. ////
  418. int baseDisplay::polymarker(const vdcPts *inPts) // emulate with disjoint polyline
  419. {
  420.   int ret = 1, i, j;
  421.   float *newFloat;
  422.   int *newInt;
  423.   vdcPts *myPts = NULL;
  424.   float defSize = 0.01 * vdcHeight; // default size
  425.   float markerSize; // marker size we shall use
  426.  
  427.   // simple descriptions of the markers as vectors, normalised to unit size
  428.   // note that we call circle routine for a circle (number 4)
  429.   const int noMarkers = 6; // for convenience; 4 + circle, 0 is a dummy
  430.   // points in descriptions
  431.   static const int noPoints[noMarkers] = {0, 2, 4, 6, 0, 4}; 
  432.   // position of descriptions
  433.   static const int offsets[noMarkers] = {0, 0, 2, 6, 12, 12}; 
  434.   // descriptions 
  435.   static float markers[32] = {
  436.     0.0, 0.0, 0.0, 0.0,                    // dot 
  437.     0.0, 0.5, 0.0, -0.5, 0.5, 0.0, -0.5, 0.0,        // plus
  438.     0.0, 0.5, 0.0, -0.5, 0.25, 0.433, -0.25, -0.433, 
  439.     -0.25, 0.433,  0.25, -0.433,             // asterisk 
  440.     0.354, 0.354, -0.354, -0.354,             
  441.     -0.354, 0.354, 0.354, -0.354};             // cross 
  442.  
  443.   ////
  444.   // figure out the size we shall use, 
  445.   if (myMarkerSize) { // been told a size
  446.     markerSize = myMarkerSize->type() ? // relative size required
  447.       myMarkerSize->f() *  defSize // else
  448.     : myMarkerSize->v()->f(); // absolute size
  449.   } else markerSize = defSize; // default
  450.  
  451.   if (myMarkerType == 4) { // use a circle
  452.     vdc *radius = NULL;
  453.     if (inPts->type()) { // real vdc's
  454.       newFloat = new float[2];
  455.       radius = new vdc((float) (markerSize/2));
  456.       myPts = new vdcPts(newFloat, 1);
  457.       for (i=0; i<inPts->no() && ret; ++i) {
  458.     newFloat[0] = inPts->fx(i);
  459.     newFloat[1] = inPts->fy(i);
  460.     ret = ret && circle(myPts, radius, 1);
  461.       }
  462.     } else { // integer vdc's
  463.       newInt = new int[2];
  464.       radius = new vdc((int) (markerSize/2));
  465.       myPts = new vdcPts(newInt, 1);
  466.       for (i=0; i<inPts->no() && ret; ++i) {
  467.     newInt[0] = inPts->ix(i);
  468.     newInt[1] = inPts->iy(i);
  469.     ret = ret && circle(myPts, radius, 1);
  470.       }
  471.     }
  472.     delete myPts;
  473.     delete radius;
  474.     return ret;
  475.   } else if ((myMarkerType > 0) && (myMarkerType < 6)) {
  476.     ////
  477.     // use disjoint polyline
  478.     float *floatPtr = markers + 2 * offsets[myMarkerType];
  479.  
  480.     if (inPts->type()) { // real vdc's
  481.       newFloat = new float[2 * noPoints[myMarkerType]];
  482.       myPts = new vdcPts(newFloat, noPoints[myMarkerType]);
  483.       for (i=0; i<inPts->no() && ret; ++i) {
  484.     for (j=0; j<noPoints[myMarkerType]; ++j) {
  485.       newFloat[2*j] = inPts->fx(i) + markerSize * floatPtr[2*j];
  486.       newFloat[2*j+1] = inPts->fy(i) + markerSize * floatPtr[2*j+1];
  487.     }
  488.     ret = ret && disPolyline(myPts);
  489.       }
  490.     } else { // integer VDC's
  491.       newInt = new int[2 * noPoints[myMarkerType]];
  492.       myPts = new vdcPts(newInt, noPoints[myMarkerType]);
  493.       for (i=0; i<inPts->no() && ret; ++i) {
  494.     for (j=0; j<noPoints[myMarkerType]; ++j) {
  495.       newInt[2*j] = inPts->ix(i) + (int) (markerSize * floatPtr[2*j]);
  496.       newInt[2*j+1] = inPts->iy(i) + (int) (markerSize * floatPtr[2*j+1]);
  497.     }
  498.     ret = ret && disPolyline(myPts);
  499.       }
  500.     }
  501.     delete myPts;
  502.   } // disjoint polyline emulation
  503.   return ret;
  504. }
  505. #ifdef macintosh
  506.  #pragma segment DIS3
  507. #endif
  508. ////
  509. // text, emulate
  510. ////
  511. int baseDisplay::text(const genText *inText)
  512. {
  513.   hersheyString *myString = new hersheyString(inText);
  514.   int ret = myString->display(this);
  515.   delete myString;
  516.   return ret;
  517. }
  518. ////
  519. // polygon
  520. ////
  521. int baseDisplay::polygon(const vdcPts *inPts) // emulate with a polyline
  522. {
  523.   int i, ret;
  524.   vdcPts *myPts;
  525.   if (inPts->type()) { // real vdc's
  526.     float *newFloat = new float[2 * (inPts->no() + 1)];
  527.     for (i=0; i<2 * inPts->no(); ++i) newFloat[i] = inPts->f(i);
  528.     newFloat[i++] = inPts->fx(0); // complete polygon
  529.     newFloat[i++] = inPts->fy(0);
  530.     myPts = new vdcPts(newFloat, inPts->no() + 1);
  531.   } else {
  532.     int *newInt = new int[2 * (inPts->no() + 1)];
  533.     for (i=0; i<2 * inPts->no(); ++i) newInt[i] = inPts->i(i);
  534.     newInt[i++] = inPts->ix(0); // complete polygon
  535.     newInt[i++] = inPts->iy(0);
  536.     myPts = new vdcPts(newInt, inPts->no() + 1);
  537.   }
  538.   ret = polyline(myPts);
  539.   delete myPts;
  540.   return ret;
  541. }
  542. ////
  543. // polygon set, emulate with a polygon
  544. ////
  545. int baseDisplay::polygonSet(const vdcPts *inPts, const int*) 
  546. {
  547.   return polygon(inPts);
  548. }
  549. ////
  550. // cell array
  551. ////
  552. int baseDisplay::cells(const cellArray *inCarray) // emulate with a polygon
  553. {
  554.   int ret = (inCarray && inCarray->corners()) ?
  555.     rectangle(inCarray->corners()) : 1;
  556.   return ret;
  557. }
  558. ////
  559. // rectangle
  560. ////
  561. int baseDisplay::rectangle(const vdcPts *inPts) // emulate with a polygon
  562. {
  563.   const int noIndices = 8;
  564.   static const int permute[noIndices] = {0, 1, 0, 3, 2, 3, 2, 1};
  565.   if (!inPts || (inPts->no() < 2)) {
  566.     myError("too few points in a rectangle");
  567.     return 1;
  568.   }
  569.   int ret, i;
  570.   vdcPts *myPts;
  571.   if (inPts->type()) { // real vdc's
  572.     float *newFloat = new float[noIndices];
  573.     for (i=0; i<noIndices; ++i) newFloat[i] = inPts->f(permute[i]);
  574.     myPts = new vdcPts(newFloat, noIndices / 2);
  575.   } else {
  576.     int *newInt = new int[8];
  577.     for (i=0; i<noIndices; ++i) newInt[i] = inPts->i(permute[i]);
  578.     myPts = new vdcPts(newInt, 4);
  579.   }
  580.   ret = polygon(myPts);
  581.   delete myPts;
  582.   return ret;
  583. }
  584. ////
  585. // circle
  586. ////
  587. int baseDisplay::circle(const vdcPts *centre, const vdc *radius, int lineOnly)
  588. {
  589.   ////
  590.   // get the beginning and ending angles
  591.   angle theta0(-0.0001, -1); // -pi - epsilon
  592.   angle theta1(0.0001, -1); // -pi + epsilon
  593.   // get a new set of points from our emulation routine
  594.   vdcPts *myPts = getArc(centre, radius, &theta0, &theta1, 1);
  595.   int ret = (lineOnly) ? polyline(myPts) : polygon(myPts);
  596.   delete myPts;
  597.   return ret;
  598. }
  599. ////
  600. // basic elliptical arc routine, defaults to circles
  601. // i.e., if r2 == NULL and rotation == 0 will get a circle
  602. ////
  603. vdcPts *baseDisplay::getArc(const vdcPts *centre, const vdc *radius,
  604.                 const angle *theta0, const angle *theta1,
  605.                 int closeType, const vdc *r2,
  606.                 const angle *rotation)
  607. {
  608. // draw a circular arc from theta0 to theta1
  609. // if closeType == 0 then we add a final point at the centre
  610. // if closeType == 1 then we add a final point duplicating the first
  611.   int i;
  612.   vdcPts *myPts;
  613. #ifdef __MSDOS__
  614.   int totalPts = 5000; // maximum no of points
  615. #else
  616.   int totalPts = 10000; // maximum no of points
  617. #endif
  618.   int noPts = (closeType >= 0) ? totalPts - 1 : totalPts;
  619.   ////
  620.   // need the rotation angle, may be null
  621.   double crot = (rotation) ? rotation->cos() : 1;
  622.   double srot = (rotation) ? rotation->sin() : 0;
  623.   ////
  624.   // get the starting angle, theta0 - rotation, and finishing angle
  625.   angle theta = (rotation) ? *theta0 - *rotation : *theta0;
  626.   angle end = (rotation) ? *theta1 - *rotation : *theta1;
  627.   ////
  628.   // now figure out a reasonable stepping angle
  629.   angle dtheta(1.0 / (1.0 + getSize(radius)), 1);
  630.   ////
  631.   // get the radii, etc.
  632.   float fx, fy;
  633.   if (centre->type()) { // real
  634.     fx = centre->fx(0);
  635.     fy = centre->fy(0);
  636.   } else {
  637.     fx = centre->ix(0);
  638.     fy = centre->iy(0);
  639.   }
  640.   float fa = radius->f(); // first radius
  641.   float fb = (r2) ? r2->f() : fa; // second radius
  642.   // note that we make sure coincident start and end -> full circle
  643.   if (centre->type()) { // real
  644.     float *newFloat = new float[totalPts * 2];
  645.     for (i=0; (i<noPts) &&
  646.      !(end.within(theta, theta + dtheta) && (i>1)); ++i) {
  647.       newFloat[2*i] = fx + fa * theta.cos() * crot -
  648.     fb * theta.sin() * srot;
  649.       newFloat[2*i+1] = fy + fb * theta.sin() * crot +
  650.     fa * theta.cos() * srot;
  651.       theta +=dtheta;
  652.     }
  653.     if (closeType == 0) { // add point at centre
  654.       newFloat[2*i] = fx;
  655.       newFloat[2*i+1] = fy;
  656.       ++i;
  657.     } else if (closeType == 1) { // close with a chord
  658.       newFloat[2*i] = newFloat[0];
  659.       newFloat[2*i+1] = newFloat[1];
  660.       ++i;
  661.     } 
  662.     myPts = new vdcPts(newFloat, i);
  663.   } else { // integer
  664.     int *newInt = new int[totalPts * 2];
  665.     for (i=0; (i<noPts) &&
  666.      !(end.within(theta, theta + dtheta) && (i>1)); ++i) {
  667.       newInt[2*i] = (int) (fx + fa * theta.cos() * crot -
  668.                fb * theta.sin() * srot);
  669.       newInt[2*i+1] = (int) (fy + fb * theta.sin() * crot +
  670.                  fa * theta.cos() * srot);
  671.       theta +=dtheta;
  672.     }
  673.     if (closeType == 0) { // add point at centre
  674.       newInt[2*i] = (int) fx;
  675.       newInt[2*i+1] = (int) fy;
  676.       ++i;
  677.     } else if (closeType == 1) { // close with a chord
  678.       newInt[2*i] = newInt[0];
  679.       newInt[2*i+1] = newInt[1];
  680.       ++i;
  681.     } 
  682.     myPts = new vdcPts(newInt, i);
  683.   }
  684.   return myPts;
  685. }
  686. ////
  687. // circular arc, 3 points, may close
  688. // emulate with a polygon or polyline
  689. // closeType == -1 => no closure
  690. // closeType == 0 => pie
  691. // closeType == 1 => chord
  692. ////
  693. int baseDisplay::arc3Pt(const vdcPts *inPts, int closeType) 
  694. {
  695. // handy macro
  696. #define SQ(in) ((double) (in) * (in))
  697.   float *c = new float[2];
  698.   int ret = 1;
  699.   if (inPts->no() < 3) return ret; // something strange
  700.   ////
  701.   // first figure out centre, radius and 2 angles from 3 points
  702.   // make sure they're not co-linear
  703.   float t1 = ((inPts->x(2) - inPts->x(0)) * (inPts->y(1) - inPts->y(0)) -
  704.           (inPts->x(1) - inPts->x(0)) * (inPts->y(2) - inPts->y(0))) * 2;
  705.   if (t1 == 0) return ret; // co-linear
  706.   ////
  707.   // more temporary variables
  708.   float t2 = inPts->x2(1) - inPts->x2(0) + inPts->y2(1) - inPts->y2(0);
  709.   float t3 = inPts->x2(2) - inPts->x2(0) + inPts->y2(2) - inPts->y2(0);
  710.   ////
  711.   // now get the center coordinates, x and y
  712.   c[0] = ((inPts->y(2) - inPts->y(0)) * t2 -
  713.       (inPts->y(1) - inPts->y(0)) * t3) / t1; 
  714.   c[1] = ((inPts->x(2) - inPts->x(0)) * t2 -
  715.       (inPts->x(1) - inPts->x(0)) * t3) / t1; 
  716.   ////
  717.   // now the radius
  718.   float r = sqrt(SQ(inPts->x(0) - c[0]) + SQ(inPts->y(0) - c[1]));
  719.   ////
  720.   // now the angles
  721.   angle theta0(inPts->y(0) - c[1], inPts->x(0) - c[0]);
  722.   angle theta1(inPts->y(1) - c[1], inPts->x(1) - c[0]);
  723.   angle theta2(inPts->y(2) - c[1], inPts->x(2) - c[0]);
  724.   ////
  725.   // we need to include the middle point between the start and end
  726.   angle *start, *end;
  727.   if (theta1.within(theta0, theta2)) {
  728.     start = &theta0;
  729.     end = &theta2;
  730.   } else {
  731.     start = &theta2;
  732.     end = &theta0;
  733.   }
  734.   ////
  735.   // prepare for the call to the arc routine
  736.   vdcPts centre(c);
  737.   vdc radius(r);
  738.   ////
  739.   // make the call
  740.   vdcPts *myPts = getArc(¢re, &radius, start, end, closeType);
  741.   ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
  742.   delete myPts;
  743.   ////
  744.   // all done
  745.   return ret;
  746. }
  747. ////
  748. // circular arc, center, 2 vectors, radius, may close
  749. // emulate with a polygon or polyline
  750. ////
  751. int baseDisplay::arcCtr(const vdcPts *inPts, vdc *radius, int closeType) 
  752. {
  753.   int ret = 1;
  754.   if (inPts->no() < 3) return ret; // something strange
  755.   ////
  756.   // first figure out 2 angles from info
  757.   angle theta0(inPts->y(1), inPts->x(1));
  758.   angle theta1(inPts->y(2), inPts->x(2));
  759.   ////
  760.   // now get the emulated points
  761.   vdcPts *myPts = getArc(inPts, radius, &theta0, &theta1, closeType);
  762.   ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
  763.   delete myPts;
  764.   ////
  765.   // all done
  766.   return ret;
  767. }
  768. #ifdef macintosh
  769.  #pragma segment DIS4
  770. #endif
  771. ////
  772. // ellipse, 3 pts (centre and 2 CDP's)
  773. // emulate with a polygon
  774. ////
  775. int baseDisplay::ellipse(const vdcPts *inPts) 
  776. {
  777.   if (inPts->no() < 3) return 1; // something strange
  778.   vdc *radius1, *radius2;
  779.  
  780.   // get the 2 radii
  781.   float r1 = sqrt(SQ(inPts->x(1) - inPts->x(0)) +
  782.           SQ(inPts->y(1) - inPts->y(0)));
  783.   float r2 = sqrt(SQ(inPts->x(2) - inPts->x(0)) +
  784.           SQ(inPts->y(2) - inPts->y(0)));
  785.   ////
  786.   // get the beginning and ending angles
  787.   angle theta0(-0.001, -1); // -pi - epsilon
  788.   angle theta1(0.001, -1); // -pi + epsilon
  789.   // figure out the angle of rotation
  790.   angle rotation(inPts->y(1) - inPts->y(0), inPts->x(1) - inPts->x(0));
  791.  
  792.   if (inPts->type()) { // real vdc's
  793.     radius1 = new vdc(r1);
  794.     radius2 = new vdc(r2);
  795.   } else { // integer
  796.     radius1 = new vdc((int) r1);
  797.     radius2 = new vdc((int) r2);
  798.   }
  799.   // get a new set of points from our emulation routine
  800.   vdcPts *myPts = getArc(inPts, radius1, &theta0, &theta1,
  801.              -1, radius2, &rotation);
  802.   int ret = polygon(myPts); // do a polygon
  803.   delete myPts;
  804.   delete radius1;
  805.   delete radius2;
  806.   return ret;
  807. }
  808. ////
  809. // elliptical arc, 5 pts plus close type
  810. // emulate with a polygon or polyline
  811. ////
  812. int baseDisplay::ellipArc(const vdcPts *inPts, int closeType) 
  813. {
  814.   if (inPts->no() < 5) return 1; // something strange
  815.   vdc *radius1, *radius2;
  816.  
  817.   // get the 2 radii
  818.   float r1 = sqrt(SQ(inPts->x(1) - inPts->x(0)) +
  819.           SQ(inPts->y(1) - inPts->y(0)));
  820.   float r2 = sqrt(SQ(inPts->x(2) - inPts->x(0)) +
  821.           SQ(inPts->y(2) - inPts->y(0)));
  822.   ////
  823.   // figure out the angle of rotation
  824.   angle rotation(inPts->y(1) - inPts->y(0), inPts->x(1) - inPts->x(0));
  825.   ////
  826.   // get the starting and ending angles
  827.   angle theta0(inPts->y(3), inPts->x(3));
  828.   angle theta1(inPts->y(4), inPts->x(4));
  829.  
  830.   if (inPts->type()) { // real vdc's
  831.     radius1 = new vdc(r1);
  832.     radius2 = new vdc(r2);
  833.   } else { // integer
  834.     radius1 = new vdc((int) r1);
  835.     radius2 = new vdc((int) r2);
  836.   }
  837.   // get a new set of points from our emulation routine
  838.   vdcPts *myPts = getArc(inPts, radius1, &theta0, &theta1,
  839.              closeType, radius2, &rotation);
  840.   int ret = (closeType >= 0) ? polygon(myPts) : polyline(myPts);
  841.   delete myPts;
  842.   delete radius1;
  843.   delete radius2;
  844.   return ret;
  845. }
  846. ////
  847. // function called at beginning of each new picture
  848. ///
  849. void baseDisplay::newPic()
  850. {
  851.   // 
  852.   // reset defaults
  853.   // control elements
  854.   //
  855.   myTrans = 1;
  856.   myClipRect = NULL;
  857.   myClip = 0; // fix later
  858.   // attributes
  859.   myLineIndex = 1;
  860.   myLineType = 1;
  861.   myLineWidth = NULL;
  862.   myMarkerIndex = 1;
  863.   myMarkerType = 3;
  864.   myMarkerSize = NULL;
  865.   myTextIndex = 1;
  866.   myFontIndex = 1;
  867.   myTextPrec = 0;
  868.   myCharExpan = 1.0;
  869.   myCharSpace = 0;
  870.   myCharHeight = NULL;
  871.   myCharOri = NULL;
  872.   myTextPath = 0;
  873.   myTextAlign = NULL;
  874.   myEdgeIndex = 1;
  875.   myEdgeType = 1;
  876.   myEdgeWidth = NULL;
  877.   myCharSetIndex = 1;
  878.   myAltCharSetIndex = 1;
  879.   myFillIndex = 1;
  880.   myIntStyle = 0;
  881.   myHatchIndex = 1;
  882.   myPatIndex = 1;
  883.   myEdgeVis = 0;
  884.   myFillRefPt = NULL;
  885. }
  886. ////
  887. // function called at beginning of each new picture body
  888.  ///
  889. void baseDisplay::newPicBody(float inWidth, float inHeight,
  890.                  float xOff, float yOff)
  891. {
  892.   // store the vdc extent
  893.   vdcWidth = inWidth;
  894.   vdcHeight = inHeight;
  895.   // get the extent of the output device
  896.   devWidth = pxlExtent()->width();
  897.   devHeight = pxlExtent()->height();
  898.   // how much do we have to scale ? (take care of non-square pixels later)
  899.   xScale = devWidth / vdcWidth;
  900.   yScale = devHeight / vdcHeight;
  901.   // use the smaller scale (largest enclosed rectangle)
  902.   useScale = (yScale < xScale) ? yScale : xScale;
  903.   // get the offsets
  904.   useOff[0] = pxlExtent()->x(0);
  905.   useOff[1] = pxlExtent()->y(0); 
  906.   // need to keep these separate for inverting devices
  907.   useOff[2] = xOff * useScale;
  908.   useOff[3] = yOff * useScale;
  909. }
  910. ////
  911. // get scaled points into integer form
  912. ////
  913. int baseDisplay::getPts(const vdcPts *inPts, int* &outPtr, int close) 
  914. {
  915.   int i;
  916.  
  917.   // get the memory
  918.   outPtr = close ? new int[inPts->no() * 2 + 2] : new int[inPts->no() * 2];
  919.  
  920.   // move over the scaled points
  921.   if (inPts->type()) { // real vdc's
  922.     if (invert()) { // need to invert the picture
  923.       for (i=0; i<inPts->no(); ++i) {
  924.     outPtr[2*i] = (int) (useOff[0] + useOff[2] + useScale * inPts->fx(i));
  925.     outPtr[2*i+1] = (int) (devHeight + useOff[3]
  926.                    - useOff[1] - useScale * inPts->fy(i));
  927.       }
  928.     } else { // normal picture
  929.       for (i=0; i<2*inPts->no(); ++i)
  930.     outPtr[i] = (int) (useOff[i % 2] + useOff[2 + (i % 2)]
  931.                + useScale * inPts->f(i));
  932.     }
  933.   } else { // integer VDC's
  934.     if (invert()) { // need to invert the picture
  935.       for (i=0; i<inPts->no(); ++i) {
  936.     outPtr[2*i] = (int) (useOff[0] + useOff[2] + useScale * inPts->ix(i));
  937.     outPtr[2*i+1] = (int) (devHeight - useOff[1]
  938.                    + useOff[3] - useScale * inPts->iy(i));
  939.       }
  940.     } else { // normal picture
  941.       for (i=0; i<2*inPts->no(); ++i)
  942.     outPtr[i] = (int) (useOff[i % 2] +  + useOff[2 + (i % 2)]
  943.                + useScale * inPts->i(i));
  944.     }
  945.   }
  946.   if (close) { // want to close the path
  947.     outPtr[2 * inPts->no()] = outPtr[0];
  948.     outPtr[2 * inPts->no() + 1] = outPtr[1];
  949.   }
  950.   return 1;
  951. }
  952. ////
  953. // get scaled points into float form
  954. ////
  955. int baseDisplay::getPts(const vdcPts *inPts, float* &outPtr, int close) 
  956. {
  957.   int i;
  958.   // get the memory
  959.   outPtr = close ? new float[inPts->no() * 2 + 2] : new float[inPts->no() * 2];
  960.  
  961.   // move over the scaled points
  962.   if (inPts->type()) { // real vdc's
  963.     if (invert()) { // need to invert the picture
  964.       for (i=0; i<inPts->no(); ++i) {
  965.     outPtr[2*i] = useOff[0] + useOff[2] + useScale * inPts->fx(i);
  966.     outPtr[2*i+1] = devHeight - useOff[1] + useOff[3]
  967.       - useScale * inPts->fy(i);
  968.       }
  969.     } else { // normal picture
  970.       for (i=0; i<2*inPts->no(); ++i)
  971.     outPtr[i] = useOff[i % 2] + useOff[2 + (i % 2)]
  972.       + useScale * inPts->f(i);
  973.     }
  974.   } else { // integer VDC's
  975.     if (invert()) { // need to invert the picture
  976.       for (i=0; i<inPts->no(); ++i) {
  977.     outPtr[2*i] = useOff[0] + useOff[2] + useScale * inPts->ix(i);
  978.     outPtr[2*i+1] = devHeight - useOff[1] + useOff[3]
  979.       - useScale * inPts->iy(i);
  980.       }
  981.     } else { // normal picture
  982.       for (i=0; i<2*inPts->no(); ++i)
  983.     outPtr[i] = useOff[i % 2] + useOff[2 + (i % 2)]
  984.       + useScale * inPts->i(i);
  985.     }
  986.   }
  987.   if (close) { // want to close the path
  988.     outPtr[2 * inPts->no()] = outPtr[0];
  989.     outPtr[2 * inPts->no() + 1] = outPtr[1];
  990.   }
  991.   return 1;
  992. }
  993. ////
  994. // get scaled points into short form
  995. ////
  996. int baseDisplay::getPts(const vdcPts *inPts, short* &outPtr, int close) 
  997. {
  998.   int i;
  999.   // get the memory
  1000.   outPtr = (close) ? new short[inPts->no() * 2 + 2]
  1001.     : new short[inPts->no() * 2];
  1002.   // move over the scaled points
  1003.   if (inPts->type()) { // real vdc's
  1004.     if (invert()) { // need to invert the picture
  1005.       for (i=0; i<inPts->no(); ++i) {
  1006.     outPtr[2*i] = (short) (useOff[0] + useOff[2] +
  1007.                    useScale * inPts->fx(i));
  1008.     outPtr[2*i+1] = (short)(devHeight - useOff[1] + useOff[3]
  1009.                 -useScale * inPts->fy(i));
  1010.       }
  1011.     } else { // normal picture
  1012.       for (i=0; i<2*inPts->no(); ++i)
  1013.     outPtr[i] = (short) (useOff[i % 2] + useOff[2 + (i % 2)]
  1014.                  + useScale * inPts->f(i));
  1015.     }
  1016.   } else { // integer VDC's
  1017.     if (invert()) { // need to invert the picture
  1018.       for (i=0; i<inPts->no(); ++i) {
  1019.     outPtr[2*i] = (short) (useOff[0] + useOff[2] +
  1020.                    useScale * inPts->ix(i));
  1021.     outPtr[2*i+1] = (short)(devHeight - useOff[1] + useOff[3]
  1022.                 - useScale * inPts->iy(i));
  1023.       }
  1024.     } else { // normal picture
  1025.       for (i=0; i<2*inPts->no(); ++i)
  1026.     outPtr[i] = (short) (useOff[i % 2] + useOff[2 + (i % 2)]
  1027.                  + useScale * inPts->i(i));
  1028.     }
  1029.   }
  1030.   if (close) { // want to close the path
  1031.     outPtr[2 * inPts->no()] = outPtr[0];
  1032.     outPtr[2 * inPts->no() + 1] = outPtr[1];
  1033.   }
  1034.   return 1;
  1035. }
  1036. ////
  1037. // attributes
  1038. ////
  1039. void baseDisplay::colrs(const colrTable*) // colour table test implementation
  1040. {
  1041. //  fprintf(stderr, "colour table set\n");
  1042. }
  1043.